package com.liuaq.liucomputer;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;

public class MainActivity extends BaseActivity implements View.OnClickListener {
    EditText input;
    TextView result, reset, divide, multipy, qi, ba, jiu, sub, si, wu, liu, add, yi, er, san, remain, zore, dot, compute;
    LinearLayout del;
    StringBuilder inputStr = new StringBuilder("");
    Toolbar mToolbar;
    ;
    boolean isChecked = true; //默认等式正确
    private Context context;
    private boolean shortAns = false; //暂时有结果

    @SuppressLint("ResourceType")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);
        context = this;
        // 初始化控件
        InitView();
        //阻止键盘弹出
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            input.setShowSoftInputOnFocus(false);
        }
        // 请求获取焦点
        input.requestFocus(); //请求获取焦点
        // 编辑框监听器
        input.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // 输入的内容变化的监听
                Log.e("输入过程中执行该方法", "文字变化");
                // 计算
                if (inputStr.length() != 0 && isChecked) { //等式正确
                    String temp = inputStr.substring(inputStr.length() - 1);
                    if (isInteger(temp)) { //最后一位是数字
                        /**
                         *  计算：中缀表达式转后缀，再计算
                         *  */

                        try {
                            Log.d("test", "on " + inputStr.toString());
                            // 得到后缀表达式
                            String postStr = transfer(inputStr.toString());
                            Log.d("test", "onFocusChange: " + postStr);
                            // 计算
                            BigDecimal ans = calculate(postStr);
                            // (c >= 48 && c <= 57)
                            String ansStr = ans.toString(); //精度为10
                            result.setText(ansStr);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count,
                                          int after) {
                // 输入前的监听
                Log.e("输入前确认执行该方法", "开始输入");

            }

        });

        // toolbar
        //生成选项菜单
        mToolbar.inflateMenu(R.menu.mymenu);
        //设置选项菜单的菜单项的点击事件
        mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                // Toast.makeText(MainActivity.this, "点击了菜单项" + item.getItemId(), Toast.LENGTH_SHORT).show();
                if (item.getItemId() == R.id.setting) {
                    Intent intent = new Intent(context,SettingActivity.class);
                    intent.putExtra("inputStr",inputStr.toString()); //传送当前数据
                    startActivity(intent);
                }
                return true;
            }
        });
        //动态设置溢出菜单的icon
        // mToolbar.setOverflowIcon(ContextCompat.getDrawable(this,R.drawable.more));
        // 借助TypedValue类来获取自定义属性
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(R.attr.moreImg, typedValue, true);
        Log.d("test", "onCreate: " + typedValue.data);
        mToolbar.setOverflowIcon(ContextCompat.getDrawable(this,typedValue.resourceId));
    }

    //result,reset,divide,multipy,del,qi,ba,jiu,sub,si
    public void InitView() {
        input = findViewById(R.id.input);
        result = findViewById(R.id.result);
        // toolbar菜单
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        // 按钮
        reset = findViewById(R.id.reset);
        reset.setOnClickListener(this);
        divide = findViewById(R.id.divide);
        divide.setOnClickListener(this);
        multipy = findViewById(R.id.multipy);
        multipy.setOnClickListener(this);
        del = findViewById(R.id.del);
        del.setOnClickListener(this);
        qi = findViewById(R.id.qi);
        qi.setOnClickListener(this);
        ba = findViewById(R.id.ba);
        ba.setOnClickListener(this);
        jiu = findViewById(R.id.jiu);
        jiu.setOnClickListener(this);
        sub = findViewById(R.id.sub);
        sub.setOnClickListener(this);

        si = findViewById(R.id.si);
        si.setOnClickListener(this);
        wu = findViewById(R.id.wu);
        wu.setOnClickListener(this);
        liu = findViewById(R.id.liu);
        liu.setOnClickListener(this);
        add = findViewById(R.id.add);
        add.setOnClickListener(this);
        yi = findViewById(R.id.yi);
        yi.setOnClickListener(this);
        er = findViewById(R.id.er);
        er.setOnClickListener(this);
        san = findViewById(R.id.san);
        san.setOnClickListener(this);
        remain = findViewById(R.id.remain);
        remain.setOnClickListener(this);
        zore = findViewById(R.id.zore);
        zore.setOnClickListener(this);
        dot = findViewById(R.id.dot);
        dot.setOnClickListener(this);
        compute = findViewById(R.id.compute);
        compute.setOnClickListener(this);

    }


/**
 * 如果数值型为double floate需要控制输出位，0.39480000可能需要手动处理后面的0
当小数后为0时不显示小数点和后面点后有数值时正常显示*/
    public static String DeleteRMBZero(String rmb) {
        while (rmb.length() != 0) {
            Log.d("text", "DeleteRMBZero0: " + rmb.length());
            if (rmb.endsWith("0")) {
                rmb = rmb.substring(0, rmb.length() - 1);
                if (rmb.endsWith(".")) {
                    rmb = rmb.substring(0, rmb.length() - 1);
                    break;
                }
            } else {
                Log.d("text", "DeleteRMBZero1: ");
                return rmb;
            }
        }
        Log.d("text", "DeleteRMBZero2: ");
        return rmb;
    }


    /**
     * 中缀表达式转后缀表达式
     *
     * @param expression
     * @return
     */
    public static String transfer(String expression) {
        //1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
        Stack<String> s1 = new Stack<>();//运算符栈
        Stack<String> s2 = new Stack<>();//储存中间结果的栈
        int index = 0;
        String keepNum = "";//用于拼接多位数
        //2.从左至右扫描中缀表达式;
        boolean only = false;
        int pos = 0;
        while (index < expression.length()) {
            char c = expression.charAt(index);

            //3.遇到操作数时，将其压s2;
            if ((c >= 48 && c <= 57) || c == '.') { //考虑小数点
                //且数字为表达式最后一位，则直接入栈s2
                if (index + 1 == expression.length() && c != '.') {
                    // s2.push(String.valueOf(c));
                    s2.push(expression.substring(pos + 1, index + 1));

                }
                keepNum += c;
                index++;
            }

            //4.如果字符c为运算符 分类讨论
            else if (isOperator(c)) {
                pos = index; // 保存运算符位置
                only = true; // 表达式中有运算符

                s2.push(keepNum);
                keepNum = "";

                //4.1如果s1为空，或栈项运算符为左括号“(”， 则直接将此运算符入栈;
                if (s1.isEmpty() || "(".equals(s1.peek())) {
                    s1.push(String.valueOf(c));
                    index++;
                }
                //4.2若运算符优先级比s1栈项运算符的高，也将运算符压入s1;
                else if (priority(c) > priority(s1.peek().charAt(0))) {
                    s1.push(String.valueOf(c));
                    index++;
                }
                //4.3否则，将s1栈项的运算符弹出并压入到s2中，再次转到(4-1)与s1中新的栈项运算符相比较;
                else {
                    s2.push(s1.pop());
                }
            }
            //5.如果遇到括号
            //5.1如果是左括号“("，则直接压入s1，继续遍历
            else if ('(' == c) {
                s2.push(keepNum);
                keepNum = "";
                s1.push(String.valueOf(c));
                index++;
            }
            //5.2如果是右括号“)”，则依次弹出s1栈顶的运算符，并压入s2,直到遇到左括号为止，此时将这一对括号丢弃
            else if (')' == c) {
                s2.push(keepNum);
                keepNum = "";
                while (true) {
                    String pop = s1.pop();
                    if ("(".equals(pop)) {
                        break;
                    }
                    s2.push(pop);
                }
                index++;
            }
            //6.重复步骤2至5，直到表达式的最右边
        }
        // 只有数字
        if (!only) s2.push(String.valueOf(keepNum));
        //遍历结束后将s1中剩余的运算符依次弹出并压入s2，再逆序输出s2就得到了后缀表达式
        //7.将s1中剩余的运算符依次弹出并压入s2
        while (!s1.isEmpty()) {
            String pop = s1.pop();
            s2.push(pop);
        }
        String suffixExpression = "";
        while (!s2.isEmpty()) {
            String pop = s2.pop();
            suffixExpression += pop + " ";
        }
        //根据空格分割
        String[] s = suffixExpression.split(" ");
        ArrayList<String> arrayList = new ArrayList<>();
        //去除多余空格
        for (String s3 : s) {
            if (!"".equals(s3)) {
                arrayList.add(s3);
            }
        }
        //8.依次弹出s2中的元素并输出，结果的逆即为中缀表达式对应的后缀表达式
        Collections.reverse(arrayList);
        String s4 = "";
        for (String s3 : arrayList) {
            s4 += s3 + " ";//此处又添加空格是为了方便给calculate函数计算，因为calculate函数需要有空格间隙的表达式
        }
        return s4;
    }


    /**
     * 计算后缀表达式
     *
     * @param suffixExpression
     */
    public static BigDecimal calculate(String suffixExpression) {
        String[] s = suffixExpression.split(" ");
        Stack<BigDecimal> stack = new Stack<>();
        MathContext mc = new MathContext(10, RoundingMode.HALF_DOWN); //精度为10
        for (String s1 : s) {
            //如果是运算符
            if (isOperator(s1.charAt(0))) {
                BigDecimal pop1 = stack.pop();
                BigDecimal pop2 = stack.pop();
                Log.d("test", "pop1" + pop1 + "pop2" + pop2 + s1.charAt(0));
                BigDecimal result = new BigDecimal("0");
                switch (s1.charAt(0)) {
                    case '×':
                        result = pop1.multiply(pop2);
                        stack.push(result);
                        break;
                    case '+':
                        result = pop1.add(pop2);
                        stack.push(result);
                        break;
                    case '-':
                        result = pop2.subtract(pop1);
                        stack.push(result);
                        break;
                    case '÷':
                        // anim需要创建精度，不然结果为无限数会报异常

                        result = pop2.divide(pop1, mc);

                        stack.push(result);
                        break;
                    case '%':
                        // 这里秋雨用double足够了
                        double pop2d = pop2.doubleValue();
                        double pop1d = pop1.doubleValue();
                        double res = mod(pop2d, pop1d);
                        // result = pop2 % pop1;
                        Log.d("test", "calculate: " + result);
                        stack.push(new BigDecimal(res));
                        break;
                    default:
                        break;
                }
            }
            //如果非运算符，就将数字入栈
            else {
                stack.push(new BigDecimal(s1));
            }
        }
        BigDecimal peek = stack.peek();
        return peek;
    }

    /**
     * 注意：只能近似值，不能精确值
     * 求浮点数的取余计算：m/n=x...r
     * m、n 不同号的话：返回 m - Math.ceil (m / n) * n; 【  ceil 向上取整  】
     * m、n 是同号的话：返回 m - Math.floor (m / n) * n;  【  floor 向下取整  】
     *
     * @param m 被除数（m为负数则余值为负数，m为正数则余值为正数）
     * @param n 除数
     * @return 余数
     */
    public static double mod(double m, double n) {
        Log.d("test", "mod: ");
        return (m / n) > 0.0 ? m - Math.floor(m / n) * n : m - Math.ceil(m / n) * n;
    }

    /**
     * 优先级
     *
     * @param c
     * @return
     */
    //为运算符分配优先级
    public static int priority(char c) {
        if (c == '×' || c == '÷' || c == '%') {
            return 1;
        }
        if (c == '-' || c == '+') {
            return 0;
        }
        if (c == '(' || c == ')') {
            return 2;
        }
        return -1;//传入的符号不是运算符
    }


    /**
     * 判断是否是一个操作符
     *
     * @param c
     * @return
     */
    public static boolean isOperator(char c) {
        if ('+' == c || '-' == c || '÷' == c || '×' == c || '%' == c) {
            return true;
        }
        return false;
    }


    /**
     * 判断字符串是否是整数
     */
    public static boolean isInteger(String value) {
        try {
            Integer.parseInt(value);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 字符串拼接及显示
     */
    @Override
    public void onClick(View v) {
        // qi,ba,jiu,si
        //wu,liu,yi,er,san,zore,compute;
        switch (v.getId()) {
            // c
            case R.id.reset:
                inputStr.delete(0, inputStr.length());
                input.setText("");
                result.setText("");
                break;
            // 删除
            case R.id.del:
                Log.d("test", "onClick: " + inputStr);
                if (inputStr.toString().length() > 0) {
                    if(inputStr.toString().length() == 1) { // 最后一个清除，需要将结果框清除
                        result.setText("");
                    }
                    inputStr.deleteCharAt(inputStr.length() - 1);
                }
                input.setText(inputStr);
                // 重新定义光标位置
                input.setSelection(inputStr.length());
                break;
            // =
            case R.id.compute:
                if(result.getText().length() != 0){
                    // 将结果放到编辑框
                    Animation animation = AnimationUtils.loadAnimation(context, R.anim.anim_input);
                    // 动画结束（俩动画同时）
                    animation.setAnimationListener(new Animation.AnimationListener() {
                        @Override
                        public void onAnimationStart(Animation animation) {

                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {
                            // 当前输入框是结果
                            shortAns = true;
                            input.setText(result.getText().toString());
                            // 清空更新 若不更新这里可以得到最原始的表达式
                            inputStr.delete(0, inputStr.length());
                            inputStr.append(result.getText().toString());
                            // 光标定位
                            input.setSelection(input.getText().length());
                            result.setText("");
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) {

                        }
                    });
                    input.startAnimation(animation);
                    Animation animation2 = AnimationUtils.loadAnimation(context, R.anim.anim_result);
                    result.startAnimation(animation2);
                }
                break;

            case R.id.dot:
                boolean haveDot = inputStr.toString().endsWith(".");
                //add地方要判断有没有超出限定最大长度14

                if (!haveDot) input.setText(inputStr.append('.'));

                input.setSelection(inputStr.length());
                break;
            case R.id.divide:
                if(shortAns){
                    shortAns = false;
                }
                boolean haveDiv = inputStr.toString().endsWith("÷");
                if (!inputStr.toString().isEmpty()) {
                    char divChar = inputStr.charAt(inputStr.toString().length() - 1);
                    // 前面有操作符
                    if (isOperator(divChar)) {
                        if (divChar == '×' || divChar == '+' || divChar == '-') {
                            inputStr.deleteCharAt(inputStr.toString().length() - 1);
                            inputStr.append("÷");
                        } else if (divChar == '.' || divChar == '%') {
                            result.setText("错误");
                            isChecked = false;
                        }
                    } else { //数字
                        inputStr.append("÷");
                    }
                }
                input.setText(inputStr.toString());
                input.setSelection(inputStr.length());
                break;
            case R.id.multipy:
                if(shortAns){
                    shortAns = false;
                }
                boolean haveMulti = inputStr.toString().endsWith("×");
                if (!inputStr.toString().isEmpty()) {
                    char mulChar = inputStr.charAt(inputStr.toString().length() - 1);
                    // 前面有操作符
                    if (isOperator(mulChar)) {
                        if (mulChar == '÷' || mulChar == '+' || mulChar == '-') {
                            inputStr.deleteCharAt(inputStr.toString().length() - 1);
                            inputStr.append("×");
                        } else if (mulChar == '.' || mulChar == '%') {
                            result.setText("错误");
                            isChecked = false;
                        }
                    } else { //数字

                        inputStr.append("×");
                    }
                }
                input.setText(inputStr.toString());
                input.setSelection(inputStr.length());
                break;
            case R.id.sub:
                if(shortAns){
                    shortAns = false;
                }
                boolean haveSub = inputStr.toString().endsWith("-");
                if (!inputStr.toString().isEmpty()) {
                    char subChar = inputStr.charAt(inputStr.toString().length() - 1);
                    // 前面有操作符
                    if (isOperator(subChar)) {
                        if (subChar == '+') {
                            // -变符号
                            inputStr.deleteCharAt(inputStr.toString().length() - 1);
                            inputStr.append("-");
                        } else if (subChar == '-') {

                        } else if (subChar == '.') {
                            result.setText("错误");
                            isChecked = false;
                        }
                    } else { //数字
                        inputStr.append("-");
                    }
                }
                input.setText(inputStr.toString());
                input.setSelection(inputStr.length());
                break;
            case R.id.add:
                if(shortAns){
                    shortAns = false;
                }
                // 最后一个数值
                boolean haveAdd = inputStr.toString().endsWith("+");
                if (!inputStr.toString().isEmpty()) {
                    char addChar = inputStr.charAt(inputStr.toString().length() - 1);
                    // 前面有操作符
                    if (isOperator(addChar)) {
                        if (addChar == '-') {
                            inputStr.deleteCharAt(inputStr.toString().length() - 1);
                            inputStr.append("+");
                        } else if (addChar == '.' || addChar == '%') {
                            result.setText("错误");
                            isChecked = false;
                        }
                    } else { //数字
                        inputStr.append("+");
                    }
                }
                input.setText(inputStr.toString());
                input.setSelection(inputStr.length());
                break;
            // 取余数
            case R.id.remain:
                // 临时结果后面符号可以继续运算
                if(shortAns){
                    shortAns = false;
                }
                boolean haveRem = inputStr.toString().endsWith("%");
                if (!inputStr.toString().isEmpty() && !isOperator(inputStr.charAt(inputStr.toString().length() - 1)))
                    inputStr.append('%');
                input.setText(inputStr.toString());
                input.setSelection(inputStr.length());
                break;
            // 数字
            case R.id.yi:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("1");
                } else {
                    inputStr.append("1");
                }
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.er:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("2");
                } else inputStr.append("2");
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.san:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("3");
                } else inputStr.append("3");
                input.setText(inputStr);
                input.setSelection(inputStr.length());

                break;
            case R.id.si:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("4");
                } else inputStr.append("4");
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.wu:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("5");
                } else inputStr.append("5");
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.liu:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("6");
                } else inputStr.append("6");
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.qi:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    Log.d("test", "onClick: ");
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("7");
                } else inputStr.append("7");
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.ba:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    Log.d("test", "onClick: ");
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("8");
                } else inputStr.append("8");
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.jiu:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                Log.d("test", "jiu: " + inputStr.toString());
                if (inputStr.toString().length() == 1 && inputStr.toString().equals("0")) {
                    Log.d("test", "onClick: ");
                    inputStr.deleteCharAt(inputStr.length() - 1);
                    inputStr.append("9");
                } else inputStr.append("9");
                input.setText(inputStr);
                input.setSelection(inputStr.length());
                break;
            case R.id.zore:
                // 先判断输入框现在是否是临时结果
                if(shortAns){
                    // 清空 方便数字输入
                    input.setText("");
                    inputStr.delete(0,inputStr.length());
                    shortAns = false;
                }
                boolean haveD = inputStr.toString().endsWith("÷");
                if (haveD) {
                    result.setText("错误");
                    isChecked = false;
                }
                if (inputStr.toString().equals("0")) {
                    break;
                } else {
                    inputStr.append('0');
                    input.setText(inputStr);
                }
                input.setSelection(inputStr.length());
            default:
                break;
        }

    }

}